<template>
  <div class="music-player"
       v-show="isReady">
    <div class="mini"
         v-show="isMini"
         @click="normalPlayer">
      <img class="mini-img"
           :src="songImage" />
    </div>
    <div class="normal"
         v-show="isNormal">
      <div class="normal-mask"
           :style="`background-image: url(${songImage})`"></div>
      <div class="normal-body">
        <div class="normal-header">
          <div class="mini-player"
               @click="smallPlayer">
            <img class="mini-img"
                 :src="songImage" />
          </div>
          <div class="music-info">
            <div class="music-name">{{player.name}}</div>
            <div class="music-signer">{{player.singer}}</div>
          </div>
          <div class="large-icon">
            <i class="el-icon-more"
               @click="openMask"></i>
          </div>
        </div>
        <div class="normal-content">
          <ul class="irc-list">
            <div class="irc-list-body"
                 :style="`transform: translate3d(0px, -${scrollHeight}px, 0px);`"
                 ref="lyricList">
              <li ref="lyricLine"
                  :class="{ actived: isActived(index) }"
                  v-for="(content,index) in ircList"
                  :key="index">{{content.txt}}</li>
            </div>
          </ul>
        </div>
        <div class="normal-footer">
          <action-bar :loop="loop"
                      @changeLoopEmit="changeLoop"
                      :is-playing="isPlaying"
                      :progress-width="progressWidth"
                      :prev="prev.bind(this)"
                      :next="next.bind(this)"
                      :pause="pause"
                      :play="play"
                      :moveEvent="moveProgress"
                      :current-time="currentTime"></action-bar>
        </div>
      </div>
    </div>
    <full-mask ref="fullMask"
               :loop="loop"
               :list="list"
               :index="index"
               :irc="ircList"
               :album-image="albumImage"
               :player="player"
               :is-actived="isActived"
               :is-playing="isPlaying"
               :progress-width="progressWidth"
               :pause="pause"
               :play="play"
               :prev="prev.bind(this)"
               :next="next.bind(this)"
               :changeLoop="changeLoop"
               :volume="volume"
               :duration="duration"
               :moveEvent="moveProgress"
               :current-time="currentTime"></full-mask>
    <audio ref="audio"
           class="audio"
           muted
           :src="playUrl"
           @play="playEvent"
           @canplay="canPlayEvent"
           @pause="pauseEvent"
           @error="errorEvent"
           @timeupdate="updateTimeEvent"
           @ended="endedEvent"></audio>
  </div>
</template>

<script>
import { fetchSongInfo, fetchProfile } from './api'
import Lyric from './lyric'
import fullMask from './components/full-mask'
import actionBar from './components/action-bar'

export default {
  name: 'musicPlayer',
  data () {
    return {
      class: 'mini',
      currentLineNum: 0,
      playingLyric: '',
      currentLyric: undefined,
      currentTime: 0,
      boldIndex: 0,
      status: 'wait',
      duration: 0,
      player: {},
      list: [],
      index: 0,
      maskVisible: true,
      scrollHeight: 0,
      loop: 0, // 播放状态 0列表循环 1单曲循环 2随机播放
      lrcLength: 0,
      authPlay: false,
      authFetchSongs: false,
      volume: 0
    }
  },
  components: {
    fullMask, actionBar
  },
  computed: {
    isMini () {
      return this.class === 'mini'
    },
    isNormal () {
      return this.class === 'normal'
    },
    isLarge () {
      return this.class === 'large'
    },
    songImage () {
      if (!this.isReady) {
        return ''
      }
      return this.player.image.img;
    },
    albumImage () {
      if (!this.isReady) {
        return ''
      }
      return this.player.album_image.img;
    },
    isReady () {
      return this.player.name
    },
    isFirst () {
      return this.index === 0
    },
    isEnd () {
      return this.index === this.length - 1
    },
    isCycle () {
      return this.loop === 0
    },
    isSingle () {
      return this.loop === 1
    },
    isRand () {
      return this.loop === 2
    },
    playUrl () {
      return this.player.full_url
      // return this.player.host + this.player.url
    },
    ircList () {
      if (!this.currentLyric) {
        return ['歌词加载中...']
      }
      return this.currentLyric.lines
    },
    isPlaying () {
      return this.status === 'playing'
    },
    length () {
      return this.list.length
    },
    progressWidth () {
      if (this.duration === 0) {
        return '0px';
      }
      return this.currentTime * 100 / this.duration + '%'
    },
    playBasic () {
      return this.list[this.index]
    }
  },
  methods: {
    // 外部调用接口
    replaceSetting (authPlay = false, authFetchSongs = false) {
      this.authPlay = authPlay
      this.authFetchSongs = authFetchSongs
      if (this.authFetchSongs) {
        fetchProfile().then(({ data: { data: list } }) => {
          if (list.length) {
            this.replaceList(list)
          }
        })
      }
    },
    async replaceList (list) {
      this.list = list
      await this.skip(0)
    },
    async insertSong (song) {
      const { list, index } = this
      const existIndex = list.findIndex(({ id }) => id === song.id)
      if (existIndex !== -1) {
        await this.skip(existIndex)
        return
      }

      list.splice(index + 1, 0, song)
      if (this.list.length === 1) {
        await this.skip(index)
      } else {
        await this.skip(index + 1)
      }
    },
    appendSong (song) {
      this.list.push(song)
    },
    // 内部调用接口
    changeVolume (volume) {
      this.$refs.audio.volume = volume
      this.volume = volume
    },
    changeLoop () {
      if (this.loop === 2) {
        this.loop = 0
        return
      }
      this.loop += 1
    },
    moveProgress (width) {
      if (this.currentLyric) {
        this.currentLyric.clearCache()
      }
      this.$refs.audio.currentTime = width * this.duration
    },
    async prev () {
      await this.skip(this.prevIndex())
    },
    async next () {
      await this.skip(this.nextIndex())
    },
    prevIndex () {
      if (this.isFirst && this.isCycle) {
        this.authPlay = false
        return this.length - 1
      }
      if (this.isSingle) {
        return this.index
      }
      if (this.isRand) {
        return this.randomIndex()
      }
      return this.index - 1
    },
    nextIndex () {
      if (this.isEnd && this.isCycle) {
        this.authPlay = false
        return 0
      }
      if (this.isSingle) {
        return this.index
      }
      if (this.isRand) {
        return this.randomIndex()
      }
      return this.index + 1
    },
    randomIndex () {
      let index;
      do {
        index = parseInt(Math.random() * this.length, 10)
      } while (index === this.index)
      return index
    },
    async skip (index) {
      if (index === false) {
        return
      }
      this.index = index
      const { data: { data } } = await fetchSongInfo(this.playBasic.song_id)
      this.player = data
    },
    async initPlayInfo () {
      this.boldIndex = 0
      this.currentLyric = new Lyric(this.player.lyric, this.handleLyric)
    },
    /****** 播放器状态管理 ******/
    play () {
      this.authPlay = true
      this.$refs.audio.play()
    },
    pause () {
      this.$refs.audio.pause()
    },
    /****** event ******/
    pauseEvent () {
      this.status = 'wait'
      this.currentLyric.stop()
    },
    playEvent () {
      this.status = 'playing'
      this.currentLyric.play()
    },
    canPlayEvent () {
      this.duration = this.$refs.audio.duration
      this.volume = this.$refs.audio.volume
    },
    errorEvent () {
      console.log('--error-- 播放器初始化失败了')
    },
    updateTimeEvent (e) {
      this.currentTime = e.target.currentTime
      this.currentLyric.seek(this.currentTime)
    },
    endedEvent () {
      this.status = 'wait'
      this.next()
    },
    /***** 样式处理 *****/
    async openMask () {
      this.smallPlayer()
      await this.$refs.fullMask.open()
      this.normalPlayer()
    },
    isActived (index) {
      return index === this.boldIndex
    },
    smallPlayer () {
      this.class = "mini"
    },
    normalPlayer () {
      this.class = 'normal'
    },
    progressMousedownEnd (e) {
      console.log(e)
    },
    handleLyric ({ lineNum, txt }) {
      this.currentLineNum = lineNum
      if (lineNum > 4) {
        const { offsetTop } = this.$refs.lyricLine[lineNum - 4]
        this.scrollHeight = offsetTop
      } else {
        this.scrollHeight = 0
      }
      this.$refs.fullMask.handleLyric({ lineNum, txt })
      this.playingLyric = txt
      this.boldIndex = lineNum
    },
  },
  watch: {
    player: {
      async handler (newVal, oldVal) {
        if (typeof (newVal) === undefined) {
          return
        }
        if (JSON.stringify(newVal) === '{}') {
          return;
        }
        if (newVal === oldVal) {
          return
        }
        await this.initPlayInfo()
        if (this.authPlay) {
          this.play()
        }
      },
      deep: true
    }
  }
}
</script>

<style lang="scss" scoped>
@import "./index.scss";
</style>